﻿using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Sharp.Platform.Mvc.Attribute;

namespace Sharp.Platform.Mvc.Route
{
    public class DomainRoute : System.Web.Routing.Route
    {
        public DomainRoute(string url, RouteValueDictionary defaults)
            : base(url, defaults, new MvcRouteHandler())
        {
        }

        public DomainRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
            : base(url, defaults, routeHandler)
        {
        }

        public DomainRoute(string url, object defaults)
            : base(url, new RouteValueDictionary(defaults), new MvcRouteHandler())
        {
        }

        public DomainRoute(string url, object defaults, object constraints)
            : base(url, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints), new MvcRouteHandler()
                )
        {
        }

        public DomainRoute(string url, object defaults, IRouteHandler routeHandler)
            : base(url, new RouteValueDictionary(defaults), routeHandler)
        {
        }

        public DomainRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints,
            RouteValueDictionary dataTokens, IRouteHandler routeHandler) : base(url, defaults, constraints,
                dataTokens, routeHandler)
        {
        }


        private static readonly Dictionary<string, string[]> AreaDic = new Dictionary<string, string[]>();

        static DomainRoute()
        {
            var filepath = Assembly.GetExecutingAssembly().CodeBase.Replace("file:///", "");
            var files = Directory.GetFiles(Path.GetDirectoryName(filepath), "*.dll").ToList();

            files.ForEach(file =>
            {
                byte[] fileData = File.ReadAllBytes(file);
                var assembly = Assembly.Load(fileData);
                var a = assembly.CustomAttributes.Any(x => x.AttributeType == typeof (AssemblyMvcAttribute));
                if (a)
                {
                    var names = assembly.GetTypes()
                        .Where(x => x.BaseType == typeof (Controller))
                        .Select(x => x.Namespace).GroupBy(x => x).Select(group => new {group.Key}).ToList();
                    var regex = new Regex(@"Areas\.(.*?)\.");

                    names.ForEach(x =>
                    {
                        AreaDic.Add(regex.Match(x.Key).Groups[1].Value, new[] {x.Key});
                    });
                }

            });
        }

        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
           

            var routeData = base.GetRouteData(httpContext);
            if (routeData == null)
            {
                return null;
            }

            if (!routeData.DataTokens.ContainsKey("area"))
            {
                string requestHost = httpContext.Request.Headers["host"];
                var simRoute = DomainRouteConfig.GetSaasRouteTarget(requestHost);

                if (simRoute == null)
                {
                    return routeData;
                }
                routeData.Values["area"] = simRoute.Area;

                try
                {
                    routeData.DataTokens["Namespaces"] = AreaDic[simRoute.Area];
                }
                catch
                {
                    var sb = new System.Text.StringBuilder();
                    sb.AppendLine("AreaDic 有数据" + AreaDic.Count);
                    foreach (var item in AreaDic)
                    {
                        sb.AppendLine(item.Key + ":" + item.Value);
                    }
                    throw new System.Exception(sb.ToString());
                }

                routeData.DataTokens["area"] = simRoute.Area;
            }

            return routeData;
        }


        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            VirtualPathData virtualPathData = base.GetVirtualPath(requestContext, values);
            object area;
            if (virtualPathData != null && virtualPathData.DataTokens.TryGetValue("area", out area))
            {
                virtualPathData.VirtualPath = virtualPathData.VirtualPath.Remove(0, area.ToString().Length + 1);
            }

            return virtualPathData;
        }
    }
}